package com.cares.event.engine;

import java.text.ParseException;
import java.util.List;
import java.util.Map;

import org.dom4j.Element;
import org.springframework.beans.BeanUtils;

import com.cares.event.constant.EventDefinitionConstant;
import com.cares.event.constant.EventFlowConstant;
import com.cares.event.constant.EventSystemConstant;
import com.cares.event.constant.XmlNodeConstant;
import com.cares.event.dao.EventExecutionDao;
import com.cares.event.dao.EventProcessDao;
import com.cares.event.dto.EventActivityDto;
import com.cares.event.dto.EventExecutionDto;
import com.cares.event.dto.Task;
import com.cares.event.entity.TEventExecution;
import com.cares.event.entity.TEventLob;
import com.cares.event.entity.TEventProcess;
import com.cares.event.listener.JsflowBeanFactory;
import com.cares.event.utils.DomUtils;
import com.cares.event.utils.EventFlowXmlUtils;
import com.cares.event.utils.EventflowUtil;


/**
 * 事件流载体
 * @author xuji
 *
 */
public class EventFlowActivity extends Thread{
	
	//流程实例运行信息
	private EventActivityDto eventActivityDto;
	
    
	public EventFlowActivity(EventActivityDto executionDto){
		this.eventActivityDto = executionDto;
	}
	
	//根据dto中的信息完成当前任务
	public void run(){
		System.out.println("任务"+eventActivityDto.getActivityName()+"开始执行！");
		//任务状态设置为：执行中
		eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_FLOW_STATE_RUN);
		try {
			finishTask();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println( "任务"+eventActivityDto.getActivityName()+"执行结束！");
	}
	
	//开始完成任务
	private void finishTask() throws ParseException{
		//1、首先将jsflowExecutionDto里的任务状态，如果是未执行的，改成执行中，如果执行中的任务，则当前任务不做
		if(EventFlowConstant.EVENT_TASK_STATE_NO.equals(eventActivityDto.getTaskStatus())){
			eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_FLOW_STATE_RUN);
			
			//当前任务所在模板的唯一属性名称
			String taskName = eventActivityDto.getActivityName();
			//当前任务的xml格式文件
			String xmlStr = eventActivityDto.getEventXml();
			
			//获取当前要执行的任务节点元素，以及任务
			Element targetTask = EventFlowXmlUtils.getTaskByAttrName(xmlStr, taskName);
			Task task = EventFlowXmlUtils.readElement(targetTask);
			if(!taskName.equals(targetTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME))){//节点name属性与流程活动表的任务不一致
				return;
			}
			
			//如果是开始节点的下一个任务，则不需要根据前一个任务执行结果判断是否执行
			String result = "";
			if(EventFlowXmlUtils.isFirstTask(xmlStr, taskName)){
				result = doTask(xmlStr, task).toString();
			}else{
				//获取流程活动表中上个任务的执行结果，上个任务的执行结果==当前任务的接受结果，执行当前任务
				if(task.getInValue().equals(eventActivityDto.getLastResult())){
					result = doTask(xmlStr, task).toString();
				}
			}
			
			//当前任务执行完成后，向内存中添加新的任务
			if(EventFlowConstant.EVENT_TASK_OUT_RESULT_SUCCESS.equals(result)){
				//1、解析xml中当前任务的下一个任务
				List<Element> nextTasks = EventFlowXmlUtils.getNextTask(xmlStr, 
											  DomUtils.getTaskAttrTo(targetTask, EventFlowConstant.EVENT_TASK_OUT_RESULT_SUCCESS),
											  task);
				if(nextTasks.size() == 1){ 
					//如果前面有并发任务，即nextTasks.get(0)为汇聚任务
					if(XmlNodeConstant.NODE_TASK_ATTR_CONCURRENT.equals(eventActivityDto.getActivityAttribute())){
						createCollectTask(xmlStr, nextTasks.get(0), result);
					}else{
						//更新下个任务的执行信息
						createNextTask(nextTasks.get(0), result,XmlNodeConstant.NODE_TASK_ATTR_NOMAL);
					}
				}else{
					//如果后续是多个并发任务
					createNextTasks(nextTasks, result);
				}
			}else{ //任务执行失败，只修改当前任务节点的状态未执行失败
				eventActivityDto.setLastResult(EventFlowConstant.EVENT_TASK_STATE_FAIL);
			}
		}
		//else{ //当前任务已经在执行或者，其他线程已经将当前任务执行完，则直接返回
		//	return;
		//}
	}
	
	/**
	 * 更新下个任务的执行信息--普通任务，流程结束节点任务
	 * @param nextTask
	 * @param result
	 * @param activityAttribute 
	 */
	private void createNextTask(Element nextTask, String result, String activityAttribute){
		EventExecutionDao jsflowExecutionDao = JsflowBeanFactory.getEventExecutionDao();
		if(XmlNodeConstant.NODE_END.equals(nextTask.getName())){ //如果下个节点是end节点，则清除活动以及内存中的任务dto
			//更新流程模板状态为：已发布
			EventProcessDao jsflowProcessDao = JsflowBeanFactory.getEventProcessDao();
			TEventProcess jsflowProcessVO = jsflowProcessDao.getEventProcess(eventActivityDto.getEventFlowId());
			jsflowProcessVO.setState(EventDefinitionConstant.EVENT_ATTR_STATE_DEPLOY);
			jsflowProcessDao.updateEventProcess(jsflowProcessVO);
			//删除执行表
			jsflowExecutionDao.deleteEventExecution(eventActivityDto.getExecutionId()); 
			//将eventActivityDto从缓存中清除
			EventSystemConstant.removeEventActivityDto(eventActivityDto);
		}else{
			//1、更改活动表信息
			TEventExecution jsflowExecutionVO = jsflowExecutionDao.getEventExecution(eventActivityDto.getExecutionId());
			jsflowExecutionVO.setActivityName(nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME)); //代办任务的节点属性名称
			jsflowExecutionVO.setLastResult(result);  //前一个任务执行后的输出结果
			jsflowExecutionVO.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO); //新的节点任务状态
			jsflowExecutionVO.setActivityAttribute(activityAttribute);
			jsflowExecutionDao.updateEventExecution(jsflowExecutionVO);
			//2、更类JsflowSystem变量的改流程执行任务
			eventActivityDto.setActivityName(nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME));
			eventActivityDto.setLastResult(result);
			eventActivityDto.setActivityAttribute(activityAttribute);
			eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO);
		}
	}
	
	/**
	 * 下个节点为并发任务
	 */
	private void createNextTasks(List<Element> nextTasks, String result){
		EventExecutionDao jsflowExecutionDao = JsflowBeanFactory.getEventExecutionDao();
		for(int i=0; i<nextTasks.size(); i++){
			TEventExecution jsflowExecutionVO = jsflowExecutionDao.getEventExecution(eventActivityDto.getExecutionId());
			if(i==0){
				//1、更改活动表信息
				jsflowExecutionVO.setActivityName(nextTasks.get(0).attributeValue(XmlNodeConstant.NODE_ATTR_NAME)); //代办任务的节点属性名称
				jsflowExecutionVO.setLastResult(result);  //前一个任务执行后的输出结果
				jsflowExecutionVO.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO); //新的节点任务状态
				jsflowExecutionVO.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_CONCURRENT);
				jsflowExecutionDao.updateEventExecution(jsflowExecutionVO);
				//2、更类JsflowSystem变量的改流程执行任务
				eventActivityDto.setActivityName(nextTasks.get(0).attributeValue(XmlNodeConstant.NODE_ATTR_NAME));
				eventActivityDto.setLastResult(result);
				eventActivityDto.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_CONCURRENT);
				eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO);
			}else{
				//复制第一个活动任务信息，并将当前任务更新到新的活动中
				TEventExecution excutionConcurrent = new TEventExecution();
				BeanUtils.copyProperties(jsflowExecutionVO, excutionConcurrent);
				excutionConcurrent.setExecutionId(null);
				excutionConcurrent.setLastResult(result);  //前一个任务执行后的输出结果
				excutionConcurrent.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO); //新的节点任务状态
				excutionConcurrent.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_CONCURRENT);
				jsflowExecutionDao.saveEventExecution(excutionConcurrent);
				
				//2、向缓存中添加新的活动任务
				EventActivityDto jsflowExecution = new EventActivityDto();
				BeanUtils.copyProperties(eventActivityDto, jsflowExecution);
				
				jsflowExecution.setActivityName(nextTasks.get(i).attributeValue(XmlNodeConstant.NODE_ATTR_NAME));
				jsflowExecution.setLastResult(result);
				jsflowExecution.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_CONCURRENT);
				jsflowExecution.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO);
				jsflowExecution.setExecutionId(excutionConcurrent.getExecutionId());
			}
		}
	}
	
	/**
	 * 下个任务为并发的汇聚任务
	 */
	private void createCollectTask(String xmlStr, Element nextTask, String result){
		EventExecutionDao jsflowExecutionDao = JsflowBeanFactory.getEventExecutionDao();
		//1、查找当前汇聚任务是否已经创建
		EventExecutionDto queryDto = new EventExecutionDto();
		queryDto.setEventFlowId(eventActivityDto.getEventFlowId());
		queryDto.setActivityName(nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME));
		 List<TEventExecution> jsflowExecutionVOs =  jsflowExecutionDao.queryEventExecutions(queryDto);
		 TEventExecution jsflowExecutionVO = jsflowExecutionDao.getEventExecution(eventActivityDto.getExecutionId());
		 if(jsflowExecutionVOs.size() == 0){
			//1、更改活动表信息
				jsflowExecutionVO.setActivityName(nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME)); //代办任务的节点属性名称
				jsflowExecutionVO.setLastResult(result);  //前一个任务执行后的输出结果
				jsflowExecutionVO.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_WAIT); //新的节点任务状态
				jsflowExecutionVO.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_MANYTOONE);
				jsflowExecutionDao.updateEventExecution(jsflowExecutionVO);
				//2、更类JsflowSystem变量的改流程执行任务
				eventActivityDto.setActivityName(nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME));
				eventActivityDto.setLastResult(result);
				eventActivityDto.setActivityAttribute(XmlNodeConstant.NODE_TASK_ATTR_MANYTOONE);
				eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_WAIT);
		 }else{
			//如果已经存在，则解析当前任务xml文件，判断前面的并发任务是否都完成
			//1、解析xml，判断前面并发任务是否全部完成
			 if(EventFlowXmlUtils.isConcurrentTaskFinish(xmlStr, nextTask.attributeValue(XmlNodeConstant.NODE_ATTR_NAME))){
				//2、如果nextTask任务的前一个是最后一个完成的任务则调整nextTask任务状态为未执行，以便等待定时器获取,如果还有未完成的并发任务，则doNothing
				jsflowExecutionVO.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO); //新的节点任务状态
				jsflowExecutionDao.updateEventExecution(jsflowExecutionVO);
				eventActivityDto.setTaskStatus(EventFlowConstant.EVENT_TASK_STATE_NO);
			 }
		 }
	}
	
	/**
	 * 1、完成节点任务，2、更改完成任务对应的节点状态 ，3、同步更新缓存中的活动任务信息中的流程xml
	 * @param task
	 * @return
	 * @throws ParseException
	 */
	private Object doTask(String xml, Task task){
		String state = EventFlowConstant.EVENT_TASK_OUT_RESULT_SUCCESS;
		if(task.getTaskType().equals(EventFlowConstant.EVENT_FLOW_TASK_TYPE_PROCEDURE)){//类型为存储过程的任务
			//解析存储过程表达式，调用存储过程
			Map<String, Object> prMap =	EventflowUtil.readProcedureFullName(task.getTaskParam1());
			String[] flowParams = new String[]{eventActivityDto.getExecutionId()+"",
					eventActivityDto.getEventName(),null,eventActivityDto.getActivityName()};
			if(prMap.containsKey(EventflowUtil.PROCEDURE_OUT)){ //有返回值
				String result = (String)JsflowBeanFactory.getProcedureService().doCallProceReturnValue(flowParams, (String)prMap.get(EventflowUtil.PROCEDURE_NAME), 
							(Object[])prMap.get(EventflowUtil.PROCEDURE_IN),(String[])prMap.get(EventflowUtil.PROCEDURE_OUT));
				if(EventDefinitionConstant.EVENT_CALL_PROCEDURE_RES_FAIL.equals(result)){
					state =  EventFlowConstant.EVENT_TASK_OUT_RESULT_FAIL;
				}
			}else{
				JsflowBeanFactory.getProcedureService().doCallProcedure(flowParams, (String)prMap.get(EventflowUtil.PROCEDURE_NAME), 
																			(Object[])prMap.get(EventflowUtil.PROCEDURE_IN));
			}
		}
		//更新流程xml文件
		updateTaskNode(xml, task, state);
		return state;
	}

	/**
	 * 更新对应的xml文件中流程节点任务的状态
	 */
	private void updateTaskNode(String xml, Task task, String result){
		String resultXml = EventFlowXmlUtils.changeNodeAttribute(xml, task, result);
		eventActivityDto.setEventXml(resultXml);
		EventProcessDao jsflowProcessDao = JsflowBeanFactory.getEventProcessDao();
		TEventProcess jsflowProcessVO = jsflowProcessDao.getEventProcess(eventActivityDto.getEventFlowId());
		TEventLob tEventLob = jsflowProcessVO.getTEventLob();
		tEventLob.setEventXml(resultXml);
		jsflowProcessDao.saveEventProcess(jsflowProcessVO);
	}
	
	/**
	 * 如果是循环执行的流程
	 * 流程启动时，清除节点任务的状态
	 */
	private void cleanTaskStateOfXml(){
		
	}
}
